package com.example.learnnetty.baseclass;

import com.example.learnnetty.constant.CommonConstant;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author ZMJ
 * @date 2020/9/21
 */
@Slf4j
public class NioDiscardServer {


    public static void startServer() throws IOException {
        // 获取选择器
        Selector selector = Selector.open();
        // 获取通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 设置非阻塞
        serverSocketChannel.configureBlocking(false);
        // 绑定连接端口
        serverSocketChannel.bind(new InetSocketAddress(CommonConstant.SOCKET_SERVER_PORT));

        log.info("服务器启动成功");

        // 降通道注册的"接受新连接"的IO事件，注册到选择器上
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 轮询感兴趣的IO就绪事件（选择键集合）
        while (selector.select() > 0) {
            // 获取选择键集合
            Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
            // 循环处理
            while (selectedKeys.hasNext()) {
                // 获取单个的选择键，并处理
                SelectionKey selectionKey = selectedKeys.next();
                // 判断key是具体的什么事件
                if (selectionKey.isAcceptable()) {
                    log.info("服务器处理OP_ACCEPT事件，转到OP_READ事件");
                    // 若选择键的IO事件是"连接就绪"事件，获得客户端连接
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // 切换为非阻塞模式
                    socketChannel.configureBlocking(false);
                    // 降该新的连接的通道的可读时间，注册到选择器上
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (selectionKey.isReadable()) {
                    log.info("服务器处理OP_READ事件");
                    // 若选择键的IO事件是"可读"的事件
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    // 读取数据，然后丢弃
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int length = 0;
                    while((length = socketChannel.read(byteBuffer)) > 0) {
                        byteBuffer.flip();
                        log.info(new String(byteBuffer.array(), 0, length));
                        byteBuffer.clear();
                    }
                    socketChannel.close();
                }
                // 移除选择键
                selectedKeys.remove();
            }
        }

        // 关闭连接
        serverSocketChannel.close();
    }

    public static void main(String[] args) throws IOException {
        startServer();
    }

}
